﻿using CodeCity.Common;
using CodeCity.SDK;
using CodeCity.UserManagement.Model;
using CodeCity.UserManagement.Service.ApplicationModel;
using CodeCity.UserMangament.Repository;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace CodeCity.UserManagement.Admin.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class SystemController : ControllerBase
    {
        private readonly GameConnection gameConnection;
        private readonly HumanRepository humanRepository;
        private readonly HosiptalRepository hosiptalRepository;
        private readonly HouseRepository houseRepository;
        private readonly GameDbContext gameDbContext;

        public SystemController(GameConnection gameConnection, HumanRepository humanRepository, HosiptalRepository hosiptalRepository, HouseRepository houseRepository, GameDbContext gameDbContext)
        {
            this.gameConnection = gameConnection;
            this.humanRepository = humanRepository;
            this.hosiptalRepository = hosiptalRepository;
            this.houseRepository = houseRepository;
            this.gameDbContext = gameDbContext;
        }

        //[HttpPost("workTime")]
        //public object GetWorkTime()
        //{
        //    return new
        //    {
        //        BeginTime = 9,
        //        EndTime = 21
        //    };
        //}


        [HttpPost("restart")]
        public async Task RestartAsync()
        {
            await gameDbContext.Database.EnsureDeletedAsync();
            await gameDbContext.Database.MigrateAsync();
        }

        [HttpPost("total")]
        public async Task<IActionResult> LoadTotal()
        {
            if (GameDateTime.Now == DateTime.MinValue)
            {
                throw new OperationException("尚未将游戏时间同步至数据库，无法统计");
            }
            return Ok(new
            {
                totalHuman = await humanRepository.CountAsync(),
                totalHouse = await houseRepository.CountAsync(),
                daylyNewHuman = await humanRepository.CountTodayAsync(),
                daylyNewHouse = await houseRepository.CountTodayAsync()
            });
        }

        [HttpGet("sync/time")]
        public Task SyncTimeAsync([FromHeader] DateTime gameTime)
        {
            GameDateTime.Now = gameTime;
            return Task.CompletedTask;
        }

        /// <summary>
        /// 获取城市数据，并同步至管理中心数据库
        /// </summary>
        /// <param name="includeHuman"></param>
        /// <returns></returns>
        [HttpGet("sync")]
        public async Task SyncCityAsync()
        {
            var cityModel = await gameConnection.GetCityAsync();
            await SyncHumenAsync(cityModel);
            await SyncHosiptalAsync(cityModel);
            await SyncHouseAsync(cityModel);

        }
        private async Task SyncHouseAsync(SDK.Contracts.CityModel cityModel)
        {
            var exists = await houseRepository.GetAllAsync();
            var existsMap = exists.ToDictionary(x => x.UnitId);
            var newHouses = new List<House>();
            foreach (var syncHouse in cityModel.Houses)
            {
                existsMap.TryGetValue(syncHouse.UnitId, out var exist);
                if (exist == null)
                {
                    newHouses.Add(new House()
                    {
                        UnitId = syncHouse.UnitId,
                        Position = syncHouse.Position,
                        BuildingTime = syncHouse.BuildingTime,
                        Humen = syncHouse.Humen,
                        MaxHumen = syncHouse.MaxHumen
                    });
                    continue;
                }
                exist.BuildingTime = syncHouse.BuildingTime;
                exist.Position = syncHouse.Position;
                exist.Humen = syncHouse.Humen;
                exist.MaxHumen = syncHouse.MaxHumen;
            }
            houseRepository.Insert(newHouses);
            await houseRepository.SaveChangesAsync();
        }
        private async Task SyncHosiptalAsync(SDK.Contracts.CityModel cityModel)
        {
            var exists = await hosiptalRepository.GetAllAsync();
            var existsMap = exists.ToDictionary(x => x.UnitId);
            var newHosiptals = new List<Hosiptal>();
            foreach (var syncHosiptal in cityModel.Hosiptals)
            {
                existsMap.TryGetValue(syncHosiptal.UnitId, out var exist);
                if (exist == null)
                {
                    newHosiptals.Add(new Hosiptal()
                    {
                        UnitId = syncHosiptal.UnitId,
                        Pregnants = syncHosiptal.Pregnants,
                        MaxPregnants = syncHosiptal.MaxPregnants,
                        Position = syncHosiptal.Position,
                        BuildingTime = syncHosiptal.BuildingTime,
                        MaxPatients = syncHosiptal.MaxPatients,
                        MaxWorkers = syncHosiptal.MaxWorkers,
                        Patients = syncHosiptal.Patients,
                        Workers = syncHosiptal.Workers
                    });
                    continue;
                }
                exist.BuildingTime = syncHosiptal.BuildingTime;
                exist.Pregnants = syncHosiptal.Pregnants;
                exist.MaxPregnants = syncHosiptal.MaxPregnants;
                exist.Position = syncHosiptal.Position;
                exist.MaxPatients = syncHosiptal.MaxPatients;
                exist.MaxWorkers = syncHosiptal.MaxWorkers;
                exist.Workers = syncHosiptal.Workers;
                exist.Patients = syncHosiptal.Patients;
            }
            hosiptalRepository.Insert(newHosiptals);
            await hosiptalRepository.SaveChangesAsync();
        }

        private async Task SyncHumenAsync(SDK.Contracts.CityModel cityModel)
        {
            var existHumen = await humanRepository.GetAllAsync();
            var existHumenMap = existHumen.ToDictionary(x => x.UnitId);
            var newHumen = new List<Human>();
            foreach (var syncHuman in cityModel.Humen)
            {
                existHumenMap.TryGetValue(syncHuman.Id, out var existHuman);
                if (existHuman == null)
                {
                    newHumen.Add(new Human()
                    {
                        BirthDay = syncHuman.BirthDay,
                        FullName = syncHuman.FullName,
                        Gender = syncHuman.Gender,
                        HomeBuildingId = syncHuman.HomeBuildingId,
                        IsAtHome = syncHuman.IsAtHome,
                        IsBusy = syncHuman.IsBusy,
                        Status = syncHuman.Status,
                        SpouseHumanId = syncHuman.SpouseHumanId,
                        UnitId = syncHuman.Id,
                        IsDead = syncHuman.IsDead,
                        WorkingBuildingId = syncHuman.WorkingBuildingId
                    });
                    continue;
                }
                existHuman.IsDead = syncHuman.IsDead;
                existHuman.BirthDay = syncHuman.BirthDay;
                existHuman.FullName = syncHuman.FullName;
                existHuman.Gender = syncHuman.Gender;
                existHuman.HomeBuildingId = syncHuman.HomeBuildingId;
                existHuman.IsAtHome = syncHuman.IsAtHome;
                existHuman.IsBusy = syncHuman.IsBusy;
                existHuman.Status = syncHuman.Status;
                existHuman.UnitId = syncHuman.Id;
                existHuman.WorkingBuildingId = syncHuman.WorkingBuildingId;
            }
            humanRepository.Insert(newHumen);
            await humanRepository.SaveChangesAsync();
        }
    }
}
